package com.shop.common;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.StandardCharsets;

@Slf4j
@Component("ftpUtil")
public class FtpUtil {

    /**
     * FTP ip地址
     */
    @Value("${host}")
    private String host;
    /**
     * FTP 端口号
     */
    @Value("${port}")
    private int port;
    /**
     * FTP 设置字符集
     */
    @Value("${charset}")
    private String charset;
    /**
     * FTP 用户名
     */
    @Value("${name}")
    private String userName;
    /**
     * FTP 密码
     */
    @Value("${password}")
    private String password;

    @Value("${filePath}")
    private String filePath;

    private FTPClient getFtpClient() {
        return new FTPClient();
    }

    /**
     * 连接ftp
     *
     * @return
     */
    private FTPClient getFtpConnect() {
        try {
            FTPClient ftpClient = getFtpClient();
            log.info("连接 {} : {} ftp服务器！", host, port);
            ftpClient.connect(host, port);
            if (!ftpClient.login(userName, password)) {
                log.info("连接 {} : {} ftp服务器失败！", host, port);
                throw new Exception("连接ftp服务器失败");
            }
            ftpClient.enterLocalActiveMode();
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.setControlEncoding(charset);
            log.info("连接 {} : {} ftp服务器成功！", host, port);
            return ftpClient;
        } catch (Exception e) {
            log.info("连接 {} : {} ftp服务器失败！", host, port);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 关闭ftp连接
     */
    private void closeFtpConnect(FTPClient ftpClient) {
        try {
            ftpClient.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 下载
     *
     * @param fileName
     * @param remotePath
     * @param savePath
     */
    public void download(String fileName, String remotePath, String savePath) {
        FileOutputStream outputStream = null;
        FTPClient  ftpClient = null;
        try {
            /* 1、连接ftp服务器 */
             ftpClient =  this.getFtpConnect();
            /* 3、切换远程目录 */
            this.changeDirectory(remotePath,ftpClient);
            /* 3、开始下载 */
            outputStream = new FileOutputStream(String.format("%s/%s", savePath, fileName));
            if (!ftpClient.retrieveFile(new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1), outputStream))
                throw new Exception(ftpClient.getReplyString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                this.closeFtpConnect(ftpClient);
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 上传
     *
     * @param file
     * @param fileName
     * @param remotePath
     * @return
     */
    public boolean upload(InputStream file, String fileName, String remotePath) {
        FTPClient ftpClient = null;
        try {
            /* 1、连接ftp服务器 */
            ftpClient  =  this.getFtpConnect();
            /* 2、创建目录  */
            this.changeDirectory(remotePath,ftpClient);
            /* 3、开始上传 */
            if (!ftpClient.storeFile(fileName, file)) log.info("上传 {} 文件到FTP失败!", fileName);
            log.info("上传 {} 文件到FTP成功!", fileName);
        } catch (IOException e) {
            log.error("FTP 上传文件失败：{}", e.getMessage());
        } finally {
            try {
                file.close();
                this.closeFtpConnect(ftpClient);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return true;
    }

    /**
     * 切换远程目录
     *
     * @param remotePath
     * @throws Exception
     */
    private void changeDirectory(String remotePath, FTPClient ftpClient) {
        /* 分解文件夹 */
        String[] directories = remotePath.split("/");
        for (String directory : directories) {
            try {
                if (ftpClient.changeWorkingDirectory(directory)) continue;
                if (ftpClient.makeDirectory(directory)) if (ftpClient.changeWorkingDirectory(directory)) continue;
                throw new Exception(String.format("更换到目录【%s】失败：%s", directory, remotePath));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void makeDirectory(boolean isHaveDirectory, String remotePath, FTPClient ftpClient) {
        int time = 0;
        while (!isHaveDirectory) {
            try {
                if (time >= 3) {
                    log.error("切换FTP远程工作目录重试超过3次失败");
                    break;
                }
                if (ftpClient.makeDirectory(remotePath)) {
                    log.info("创建FTP远程保存文件文件夹 {} 成功.", remotePath);
                    isHaveDirectory = ftpClient.changeWorkingDirectory(remotePath);
                } else {
                    time++;
                    log.error("创建FTP远程保存文件文件夹 {} 失败.", remotePath);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
